Types for Safe Locking
نویسندگان
چکیده
A race condition is a situation where two threads manipulate a data structure simultaneously, without synchronization. Race conditions are common errors in multithreaded programming. They often lead to unintended nondeterminism and wrong results. Moreover, they are notoriously hard to diagnose, and attempts to eliminate them can introduce deadlocks. In practice, race conditions and deadlocks are often avoided through prudent programming discipline: protecting each shared data structure with a lock and imposing a partial order on lock acquisitions. In this paper we show that this discipline can be captured (if not completely, to a significant extent) through a set of static rules. We present these rules as a type system for a concurrent, imperative language. Although weaker than a full-blown program-verification calculus, the type system is effective and easy to apply. We emphasize a core, first-order type system focused on race conditions; we also consider extensions with polymorphism, existential types, and a partial order on lock types. 1 Races, Locks, and Types Programming with multiple threads introduces a number of pitfalls, such as race conditions and deadlocks. A race condition is a situation where two threads manipulate a data structure simultaneously, without synchronization. Race conditions are common, insidious errors in multithreaded programming. They often lead to unintended nondeterminism and wrong results. Moreover, since race conditions are timing-dependent, they are notoriously hard to track down. Attempts to eliminate race conditions by using lock-based synchronization can introduce other errors, in particular deadlocks. A deadlock occurs when no thread can make progress because each is blocked on a lock held by some other thread. In practice, both race conditions and deadlocks are often avoided through careful programming discipline [5]. Race conditions are avoided by protecting each shared data structure with a lock, and accessing the data structure only when the protecting lock is held. Deadlocks are avoided by imposing a strict partial order on locks and ensuring that each thread acquires locks only in increasing order. However, this programming discipline is not well supported by existing development tools. It is difficult to check if a program adheres to this discipline, and easy to write a program that does not by mistake. A single unprotected access in an otherwise correct program can produce a timing-dependent race condition whose cause may take weeks to identify. In this paper we show that this programming discipline can be captured through a set of static rules. We present those rules as a type system for a concurrent, imperative language. We initially consider a first-order type system focused on race conditions. The type system supports dynamic thread creation and the dynamic allocation of locks and reference cells. We then consider extensions, such as universal and existential types, that increase the expressiveness of the system. We also outline an extension that eliminates deadlock by enforcing a strict partial order on lock acquisitions. Since the programming discipline dictates that a thread can access a shared data structure only when holding a corresponding lock, our type systems provide rules for proving that a thread holds a given lock at a given program point. The rules rely on singleton lock types. A singleton lock type is the type of a single lock. Therefore, we can represent a lock l at the type level with the singleton lock type that contains l, and we can assert that a thread holds l by referring to that type rather than to the lock l. The type of a reference cell mentions both the type of the contents of the cell and the singleton lock type of the lock that protects the cell. Thus, singleton lock types provide a simple way of injecting lock values into the type level. A set of singleton lock types forms a permission. During typechecking, each expression is analyzed in the context of a permission; including a singleton lock type in the permission amounts to assuming that the corresponding lock is held before evaluation of the expression. In addition, a permission decorates each function type and each function definition, representing the set of locks that must be held before a function call. We study typechecking rather than type inference, so we do not show how to infer which lock protects a reference cell or which permission may decorate a function definition. We simply assume that the programmer can provide such information explicitly, and leave type inference as an open problem. There is a significant body of previous work in this area, but most earlier approaches are either unsound (i.e., do not detect all race conditions) [22], deal only with finite state spaces [7, 10, 12], or do not handle mainstream sharedvariable programming paradigms [1, 16]. In contrast, we aim to give a sound type system for statically verifying the absence of race conditions in a programming language with shared variables. We defer a more detailed discussion of related work to section 7. The next section describes a first-order type system for a concurrent, imperative language. Section 3 presents the operational semantics of the language, which is the basis for the race-freeness theorem of section 4. Section 5 extends the type system with universal and existential types. Section 6 further extends the type system in order to prevent deadlocks. Section 7 discusses related work. We conclude with section 8. For the sake of brevity, we omit proofs. Moreover, we give the type systems of sections 5 and 6 without corresponding operational semantics and correctness theorems. The operational semantics are straightforward. To date, we have studied how to extend the correctness theorem of section 4 to the type systems of section 5, but only partially to that of section 6. V ∈ Value = c | x | λx : t. e c ∈ Const = unit x, y ∈ Var e ∈ Exp = V | e e | refme | !e | e := e | fork e | new-lock x :m in e | sync e e s, t ∈ Type = Unit | t →p t | Refmt | m m,n, o ∈ TypeVar p, q ∈ Permission = P(TypeVar) Fig. 1. A concurrent, imperative language. 2 First-order Types against Races We start by considering a first-order type system focused on race conditions, and defer deadlock prevention to section 6. We formulate our type system for the concurrent, imperative language described in figure 1. The language is callby-value, and includes values (constants, variables, and function definitions), applications, and the usual imperative operations on reference cells: allocation, dereferencing, and assignment. Although the language does not include explicit support for recursion, recursive functions can be encoded using reference cells, as described in section 2.2 below. The language allows multithreaded programs by including the operation fork e which spawns a new thread for the evaluation of e. This evaluation is performed only for its effect; the result of e is never used. Locks are provided for thread synchronization. A lock has two states, locked and unlocked, and is initially unlocked. The expression new-lock x :m in e dynamically allocates a new lock, binds x to that lock, and then evaluates e. It also introduces the type variable m which denotes the singleton lock type of the new lock. The expression sync e1 e2 is evaluated in a manner similar to Java’s synchronized statement [14]: the subexpression e1 is evaluated first, and should yield a lock, which is then acquired; the subexpression e2 is then evaluated; and finally the lock is released. The result of e2 is returned as the result of the sync expression. While evaluating e2, the current thread is said to hold the lock, or, equivalently, is in a critical section on the lock. Any other thread that attempts to acquire the lock blocks until the lock is released. Locks are not reentrant; that is, a thread cannot reacquire a lock that it already holds. A new thread does not inherit locks held by its parent thread.
منابع مشابه
Pre-Analysis Locking: A Safe and Deadlock Free Locking Policy
A safe and deadlock free lock policy is introduced, called pre-analysis locking. Pre-analysis locking is based on an efficient geometric algorithm which inserts lock and unlock operations into the transactions. Pre-analysis locking is the first safe and deadlock free general locking policy which is not a variant of two-phase locking. It is an approach conceptually different from policies follow...
متن کاملStrategized Locking, Thread-safe Interface, and Scoped Locking Patterns and Idioms for Simplifying Multi-threaded C++ Components
Developing multi-threaded applications is hard since incorrect use of locks can cause subtle and pernicious errors. Likewise, developing multi-threaded reusable components is hard since it can be time-consuming to customize components to support new, more efficient locking strategies. This paper describes a pair of patterns, Strategized Locking and Thread-safe Interface, and a C++ idiom, Scoped...
متن کاملFirst Metatarsophalangeal Joint Arthrodesis: A Retrospective Comparison of Crossed-screws, Locking and Non-Locking Plate Fixation with Lag Screw
Background:Locking plate fixation is increasingly used for first metatarsophalangeal joint (MTP-I) arthrodesis. Still there is few comparable clinical data regarding this procedure. Methods:We retrospectively evaluated 60 patients who received an arthrodesis of the MTP-I between January 2008 and June 2010. With 20 patients each we performed a locking plate fixation with lag screw, arthrodesis w...
متن کاملHow to Care for Implanted Ports
Implantable ports are used for intravenous infusion therapy and play an important role in management of oncology patients. These ports are best suited for patients requiring long-term therapy (>4 weeks). Implanted ports provide reliable venous access protect peripheral access increase patients’ comfort through reducing repeated and difficult vein punctures allow for safe and comfortable admi...
متن کاملImaging Evaluation of the Safe Region for Distal Locking Screw of Proximal Femoral Nail Anti-Rotation in Patients with Proximal Femoral Fracture
BACKGROUND Proximal femoral nail anti-rotation (PFNA) is a standard femoral intertrochanteric fracture operation. Iatrogenic vascular injury, although uncommon, is a reported complication of PFNA surgery as well as a complication of hip fracture surgery. This study aimed to compare the safety and best use of the distal locking screw in 170 mm PFNA and 240 mm PFNA devices, and to determine the s...
متن کاملEvaluation of Phase Locking and Cross Correlation Methods for Estimating the Time Lag between Brain Sites: A Simulation Approach
Introduction: Direction and latency of electrical connectivity between different sites of brain explains brain neural functionality. We compared efficiency of cross correlation and phase locking methods in time lag estimation which are based on local field potential (LFP) and LFPspike signals, respectively. Methods: Signals recorded from MT area of a macaque’s brain was used in a simulation ...
متن کامل